<?php
/**
 * XGPHP 轻量级PHP框架
 * @link http://xgphp.xg3.cn
 * @version 2.0.0
 * @license http://www.apache.org/licenses/LICENSE-2.0
 * @author 讯高科技 <xungaokeji@qq.com>
*/
namespace xg;
use \helper\Arr;

class Where {
	protected $data=[];
	protected $alias=[];
	
	protected $tableInfo=[];
	protected $bind=[];
	protected $bindIndex=0;
	protected $sql='';
	
	// TODO
	// public function alias($alias){
	// 	$this->alias=$alias;
	// 	return $this;
	// }
	public function reset(){
		$this->alias=[];
		$this->data=[];
		$this->resetSql();
		return $this;
	}
	protected function resetSql(){
		$this->bind=[];
		$this->bindIndex=0;
		$this->sql='';
	}
	protected function paramName(){
		return '[?where:'.($this->bindIndex++).']';
	}
	protected function buildSql($datai){
		if($this->bindIndex>0){
			$logical=$datai['logical']?$datai['logical']:'and';
		}
		if(!($field=trim($datai['field'],'`')) and $datai['type']!='string' and $datai['type']!='sub'){
			throw new Exception('miss field name');
		}
		if($datai['type']=='range'){
			$startName=$this->paramName();
			$endName=$this->paramName();
			$this->bind[$startName]=$datai['start'];
			$this->bind[$endName]=$datai['end'];
			$not=$datai['not']?' not ':'';
			$sql=" `$field` $not $startName and $endName ";
		}elseif($datai['type']=='like'){
			$paramName=$this->paramName();
			$this->bind[$paramName]=$datai['pattern'];
			$operator=$datai['not']?' not like ':' like ';
			$sql=" `$field` $operator $paramName ";
		}elseif($datai['type']=='condition'){
			$operator=$datai['operator'];
			$paramName=$this->paramName();
			$this->bind[$paramName]=$datai['value'];
			$sql=" `$field` $operator $paramName ";
		}elseif($datai['type']=='null'){
			$operator=$datai['not']?' not null ':' is null ';
			$sql=" `$field` $operator ";
		}elseif($datai['type']=='sub'){
			$subData=$datai['bind'];
			$subSql='';
			foreach($subData as $dataj){
				$subSql.=$this->buildSql($dataj);
			}
			$sql='('.trim($subSql).')';
		}elseif($datai['type']=='string'){
			$sql='('.trim($datai['string']).')';
		}elseif(isset($datai['sql']) and isset($datai['bind'])){
			$dataSql=$datai['sql'];
			foreach($datai['bind'] as $param=>$dataj){
				$newParamName=$this->paramName();
				$dataSql=str_replace($param,$newParamName,$dataSql);
				$this->bind[$newParamName]=$dataj;
			}
		}
		if($sql=trim($sql)){
			if(stripos($sql,'[?pk]')!==false){
				if(!$this->tableInfo['pk']){
					throw new Exception('miss primary key');
				}
				$sql=str_ireplace('[?pk]',$this->tableInfo['pk'],$sql);
			}
			return " $logical $sql ";
		}
		return '';
	}
	public function sqlData() {
		$this->resetSql();
		foreach($this->data as $datai){
			$this->sql.=$this->buildSql($datai);
		}
		return ['sql'=>$this->sql,'bind'=>$this->bind];
	}
	public function tableInfo(array $info){
		$this->tableInfo=$info;
		return $this;
	}
	public function data(){
		return $this->data;
	}
	public function between($field,$start,$end,$logical='and'){
		return $this->where($field,'between',[$start,$end],$logical);
	}
	public function notBetween($field,$start,$end,$logical='and'){
		return $this->where($field,'not between',[$start,$end],$logical);
	}
	public function isNull($field,$logical='and'){
		return $this->where($field,'null',null,$logical);
	}
	public function notNull($field,$logical='and'){
		return $this->where($field,'not null',null,$logical);
	}
	public function whereOr($field,$operator=null,$value=null){
		return $this->where($field,$operator,$value,'or');
	}
	public function where($field,$operator=null,$value=null,$logical='and'){
		// 操作符列表
		$sym=array('neq'=>'!=','eq'=>'=','egt'=>'>=','gt'=>'>','elt'=>'<=','lt'=>'<');
		
		// 闭包 通过闭包处理条件 然后继续处理
		if($field instanceof \Closure){
			$field=$field(new self()/* TODO ->alias($this->alias) */);
		}
		
		if(is_object($field))
		// where对象
		{
			if($field instanceof self){
				$data=$field->data();
				if($$data){
					$this->data[]=['type'=>'sub','bind'=>$data,'logical'=>$logical];
				}
			}
		}
		elseif(is_array($field))
		// 判断是否为where条件信息
		{
			if($field['type']){
				if(
					($field['type']=='condition' and isset($field['field']) and isset($field['operator']) and isset($field['value']) and isset($field['logical']))
					or ($field['type']=='sub' and isset($field['bind']) and isset($field['logical']))
					or ($field['type']=='range' and isset($field['field']) and isset($field['start']) and isset($field['end']) and isset($field['logical']))
					or ($field['type']=='like' and isset($field['field']) and isset($field['pattern']) and isset($field['logical']))
					or ($field['type']=='null' and isset($field['field']) and isset($field['logical']))
					or ($field['type']=='string' and isset($field['string']) and isset($field['logical']))
				){
					$this->data[]=$field;
				}
			}
			// 判断是否为where数据信息
			elseif(isset($field['sql']) and isset($field['bind']))
			{
				$this->data[]=$field;
			}else{
				if(is_array($field[0]))
				// 如果是多维数组
				{
					foreach($field as $condi){
						$this->where($condi);
					}
				}
				// 如果是键值对
				elseif(is_string(array_keys($field)[0]))
				{
					foreach($field as $key=>$value){
						if(is_array($value)){
							$this->where($key,'in',$value);
						}else{
							$this->where($key,'=',$value);
						}
					}
				}
				elseif(count($field)==3)
				// 条件数组
				{
					$this->where($field[0],$field[1],$field[2]);
				}
			}
		}elseif(is_string($field) and strpos($field,'|')>0){// 多字段查询
			$this->where(function($obj)use($field,$operator,$value){
				$arr=Arr::split($field,'|');
				foreach($arr as $v){
					$obj->whereOr($v,$operator,$value);
				}
				return $obj;
			});
		}
		elseif(is_numeric($field))
		// 主键查询
		{
			$this->where('[?pk]','=',$field,$logical);
		}
		elseif(is_array($operator))
		// 如果第二个条件为数组 那么是in查询
		{
			$this->where($field,'in',$operator,$logical);
		}
		elseif(!is_null($value))
		// 第三个参数为值
		{
			$operator=trim(strtolower($operator));
			if(!$operator){
				$operator='=';
			}elseif($sym[$operator]){
				$operator=$sym[$operator];
			}
			if($operator=='in'){
				$value=Arr::split($value);
			}
			if($operator=='between'){// between
				$this->data[]=['type'=>'range','field'=>$field,'start'=>$value[0],'end'=>$value[1],'logical'=>$logical];
			}elseif($operator=='not between'){// not between
				$this->data[]=['type'=>'range','field'=>$field,'start'=>$value[0],'end'=>$value[1],'logical'=>$logical,'not'=>true];
			}elseif($operator=='null'){// is null
				$this->data[]=['type'=>'null','field'=>$field,'logical'=>$logical];
			}elseif($operator=='not null'){// is not null
				$this->data[]=['type'=>'null','field'=>$field,'logical'=>$logical,'not'=>true];
			}elseif($operator=='like'){// like
				$this->data[]=['type'=>'like','field'=>$field,'pattern'=>$value,'logical'=>$logical];
			}elseif($operator=='not like'){// not like
				$this->data[]=['type'=>'like','field'=>$field,'pattern'=>$value,'logical'=>$logical,'not'=>true];
			}else{// 默认
				$this->data[]=['type'=>'condition','field'=>$field,'operator'=>$operator,'value'=>$value,'logical'=>$logical];
			}
		}elseif(!is_null($operator)){// 第二个参数为值
			$this->where($field,'=',$operator,$logical);
		}elseif(is_string($field)){// 直接传入条件字符串
			$this->data[]=['type'=>'string','string'=>$field,'logical'=>$logical];
		}
		return $this;
	}
}
?>